﻿
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace CLVisionHalconWorker
{
    public class HalconCaller
    {
        #region "API"
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);

        public string ReadValue(string section, string key, string Filepath)
        {
            StringBuilder temp = new StringBuilder(1024);
            int i = GetPrivateProfileString(section, key, "", temp, 1024, Filepath);
            return temp.ToString();
        }
        #endregion

        #region 变量
        private HDevEngine myEngine;
        public HDevProgramCall programCall;

        private HDevProcedure runProcedure;
        public HDevProcedure RunProcedure { get => runProcedure; set => runProcedure = value; }

        private HDevProcedureCall retProcedureCall;
        public HDevProcedureCall RetProcedureCall { get => retProcedureCall; set => retProcedureCall = value; }


        private HTuple _InputIconicNames;
        private HTuple _InputCtrlNames;
        private HTuple _OutputIconicNames;
        private HTuple _OutputCtrlNames;
        private List<string> procedurePaths = new List<string>();
        public HTuple InputIconicNames { get => _InputIconicNames; set => _InputIconicNames = value; }
        public HTuple InputCtrlNames { get => _InputCtrlNames; set => _InputCtrlNames = value; }
        public HTuple OutputIconicNames { get => _OutputIconicNames; set => _OutputIconicNames = value; }
        public HTuple OutputCtrlNames { get => _OutputCtrlNames; set => _OutputCtrlNames = value; }
        public List<string> ProcedurePaths { get => procedurePaths; set => procedurePaths = value; }

        #endregion

        /// <summary>
        /// 初始化Halcon引擎
        /// </summary>
        /// <param name="procedurePath">procedure路径</param>
        /// <param name="logPath">日志路径</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public virtual bool InitHDevEngine(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "InitHDevEngine Success!";
            try
            {
                myEngine = new HDevEngine();
                //设置文档语言，要想获取文档参数，必须先设置语言
                myEngine.SetEngineAttribute("docu_language", "zh_CN");
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"InitHDevEngine Fail！+ {ex.Message} + 可能原因：环境变量Path设置有误";
                return false;
            }
        }
        /// <summary>
        /// 添加Procedure路径
        /// </summary>
        /// <param name="procedurePath">Procedure路径</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool AddProcedurePath(string procedurePath, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "AddprocedurePath Success!";
            try
            {
                if (!ProcedurePaths.Contains(procedurePath))
                {
                    ProcedurePaths.Add(procedurePath);
                }
                myEngine.AddProcedurePath(procedurePath);
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "AddprocedurePath Fail!" + ex.Message;
                return false;
            }
        }

        public bool SetProcedurePath(string procedurePath, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "SetProcedurePath Success!";
            try
            {
                if (!ProcedurePaths.Contains(procedurePath))
                {
                    ProcedurePaths.Add(procedurePath);
                }
                myEngine.SetProcedurePath(procedurePath);
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "SetProcedurePath Fail!" + ex.Message;
                return false;
            }
        }
        /// <summary>
        /// 添加Procedure路径数组
        /// </summary>
        /// <param name="procedurePath">Procedure路径</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool AddProcedurePath(string[] procedurePath, out int ErrorCode, out string ErrorText)
        {
            try
            {
                for (int i = 0; i < procedurePath.Length; i++)
                {
                    if (!ProcedurePaths.Contains(procedurePath[i]))
                    {
                        ProcedurePaths.Add(procedurePath[i]);
                    }
                    myEngine.AddProcedurePath(procedurePath[i]);
                }
                ErrorCode = 0;
                ErrorText = "AddprocedurePaths Success!";
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "AddprocedurePaths Fail!" + ex.Message;
                return false;
            }
        }
        /// <summary>
        /// 获取Procedure名称
        /// </summary>
        /// <param name="showProcedurePath">显示文件夹内部的Procedure名称</param>
        /// <param name="procedureNames">Procedure名称</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool GetProcedureNames(string[] showProcedurePath, out string[] procedureNames, out int ErrorCode, out string ErrorText, SearchOption searchOption = SearchOption.AllDirectories)
        {
            ErrorCode = 0;
            ErrorText = "GetProcedureNames Success!";
            List<string> tempLs = new List<string>();
            try
            {
                for (int i = 0; i < ProcedurePaths.Count; i++)
                {
                    for (int m = 0; m < showProcedurePath.Length; m++)
                    {
                        if (ProcedurePaths[i] == showProcedurePath[m])
                        {
                            string[] files = Directory.GetFiles(ProcedurePaths[i], "*.hdvp", searchOption);
                            for (int j = 0; j < files.Length; j++)
                            {
                                string path = files[j];
                                string procedureName = Path.GetFileNameWithoutExtension(path);
                                tempLs.Add(procedureName);
                            }
                        }
                    }
                }
                procedureNames = tempLs.ToArray();
                return true;
            }
            catch (Exception ex)
            {
                procedureNames = null;
                ErrorCode = -1;
                ErrorText = "GetProcedureNames Fail!" + ex.Message;
                return false;
            }
        }
        /// <summary>
        /// 加载Procedure
        /// </summary>
        /// <param name="procedureName">Procedure名称</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool LoadProcedure(string procedureName, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "LoadProcedure Success!";
            try
            {
                runProcedure = new HDevProcedure(procedureName);
                RetProcedureCall = new HDevProcedureCall(runProcedure);

                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "LoadProcedure Fail!" + ex.Message;
                return false;
            }

        }
        /// <summary>
        /// 获取Procedure参数名称
        /// </summary>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool GetProcedureParNames(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "GetProcedureParNames Success!";
            try
            {
                _InputIconicNames = runProcedure.GetInputIconicParamNames();
                _InputCtrlNames = runProcedure.GetInputCtrlParamNames();
                _OutputIconicNames = runProcedure.GetOutputIconicParamNames();
                _OutputCtrlNames = runProcedure.GetOutputCtrlParamNames();
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "GetProcedureParNames Fail!" + ex.Message;
                return false;
            }

        }
        /// <summary>
        /// 调用Procedure
        /// </summary>
        /// <param name="procedureName">Procedure名称</param>
        /// <param name="hObj_InputIconic">图像输入</param>
        /// <param name="hObj_OutputIconic">图像输出</param>
        /// <param name="hTuple_InputCtrl">控制输入</param>
        /// <param name="hTuple_OutputCtrl">控制输出</param>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool CallProcedure(string procedureName, HObject[] hObj_InputIconic, out HObject[] hObj_OutputIconic, HTuple hTuple_InputCtrl, out HTuple hTuple_OutputCtrl, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "CallProcedure Success!";
            hObj_OutputIconic = null;
            hTuple_OutputCtrl = null;



            if (this.RunProcedure.Name != procedureName)
            {
                LoadProcedure(procedureName, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    return false;
                }
            }

            GetProcedureParNames(out ErrorCode, out ErrorText);
            if (ErrorCode == -1)
            {
                return false;
            }
            try
            {
                for (int i = 0; i < hObj_InputIconic?.Length; i++)
                {
                    HObject hObject = hObj_InputIconic[i];
                    string name = InputIconicNames[i].S;
                    RetProcedureCall.SetInputIconicParamObject(name, hObject);
                }

                for (int i = 0; i < hTuple_InputCtrl?.Length; i++)
                {
                    RetProcedureCall.SetInputCtrlParamTuple(InputCtrlNames[i].S, hTuple_InputCtrl[i]);
                }

                try
                {
                    //运行 Procedure
                    RetProcedureCall.Execute();
                }
                catch (Exception ex)
                {
                    ErrorCode = -1;
                    ErrorText = "CallProcedure Fail！可能原因：Halcon输入参数赋值异常" + ex.Message;
                    hObj_OutputIconic = null;
                    hTuple_OutputCtrl = null;
                    return false;
                }


                //创建 Temp_hObj_OutputIconic 集合和 Temp_hTuple_OutputCtrl，用于存储 Procedure 的输出结果
                List<HObject> Temp_hObj_OutputIconic = new List<HObject>();
                HTuple Temp_hTuple_OutputCtrl = new HTuple();

                //遍历输出结果，并存储值 Temp_hObj_OutputIconic 集合和 Temp_hTuple_OutputCtrl
                for (int i = 0; i < OutputIconicNames?.Length; i++)
                {
                    HObject hObject = RetProcedureCall.GetOutputIconicParamObject(OutputIconicNames[i].S);
                    Temp_hObj_OutputIconic.Add(hObject);
                }

                for (int i = 0; i < OutputCtrlNames?.Length; i++)
                {
                    HTuple hTuple = RetProcedureCall.GetOutputCtrlParamTuple(OutputCtrlNames[i].S);
                    Temp_hTuple_OutputCtrl[i] = hTuple;
                }
                //将存储结果输出
                hObj_OutputIconic = Temp_hObj_OutputIconic.ToArray();
                hTuple_OutputCtrl = Temp_hTuple_OutputCtrl;
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "CallProcedure Fail!" + ex.Message;
                hObj_OutputIconic = null;
                hTuple_OutputCtrl = null;
                return false;
            }
        }


        /* *
         * HTupleVector hTuple_InputCtrl和out HTupleVector hTuple_OutputCtrl是为了满足NC需求
         * Halcon可能输出数组（多个元素）/输入数组,但NC无接收数组的数据类型,通过HTupleVector进行中
         * */
        /// <summary>
        /// 调用Procedure
        /// </summary>
        /// <param name="procedureName"></param>
        /// <param name="hObj_InputIconic"></param>
        /// <param name="hObj_OutputIconic"></param>
        /// <param name="hTuple_InputCtrl"></param>
        /// <param name="hTuple_OutputCtrl"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <returns></returns>
        public bool CallProcedure(string procedureName, HObject[] hObj_InputIconic, out HObject[] hObj_OutputIconic, HTupleVector hTuple_InputCtrl, out HTupleVector hTuple_OutputCtrl, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "CallProcedure Success!";
            hObj_OutputIconic = null;
            hTuple_OutputCtrl = null;

            //判断已经加载的procedure，是否是要运行的
            if (this.RunProcedure.Name != procedureName)
            {
                LoadProcedure(procedureName, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    return false;
                }
            }

            //获取procedure的图标参数和控制参数名称
            GetProcedureParNames(out ErrorCode, out ErrorText);
            if (ErrorCode == -1)
            {
                return false;
            }
            //传参运行procedure
            try
            {
                for (int i = 0; i < hObj_InputIconic?.Length; i++)
                {
                    HObject hObject = hObj_InputIconic[i];
                    string name = InputIconicNames[i].S;
                    if (hObject == null)
                    {
                        ErrorCode = -1;
                        ErrorText = $"CallProcedure Fail! {name}参数的值为空！请检查！";
                        return false;
                    }
                    RetProcedureCall.SetInputIconicParamObject(name, hObject);
                }

                for (int i = 0; i < hTuple_InputCtrl?.Length; i++)
                {
                    string name = InputCtrlNames[i].S;
                    HTuple hTuple = hTuple_InputCtrl[i].T;
                    if (hTuple == null || hTuple.Length == 0)
                    {
                        ErrorCode = -1;
                        ErrorText = $"CallProcedure Fail! {name}参数的值为空！请检查！";
                        return false;
                    }
                    RetProcedureCall.SetInputCtrlParamTuple(name, hTuple);
                }

                try
                {
                    //运行 Procedure
                    RetProcedureCall.Execute();
                }
                catch (Exception ex)
                {
                    ErrorCode = -1;
                    ErrorText = "CallProcedure Fail！可能原因：Halcon输入参数赋值异常" + ex.Message;
                    hObj_OutputIconic = null;
                    hTuple_OutputCtrl = null;
                    return false;
                }

                //创建 Temp_hObj_OutputIconic 集合和 Temp_hTuple_OutputCtrl，用于存储 Procedure 的输出结果
                List<HObject> Temp_hObj_OutputIconic = new List<HObject>();
                HTupleVector Temp_hTuple_OutputCtrl = new HTupleVector(1);

                //遍历输出结果，并存储值 Temp_hObj_OutputIconic 集合和 Temp_hTuple_OutputCtrl
                for (int i = 0; i < OutputIconicNames?.Length; i++)
                {
                    HObject hObject = RetProcedureCall.GetOutputIconicParamObject(OutputIconicNames[i].S);
                    Temp_hObj_OutputIconic.Add(hObject);
                }

                for (int i = 0; i < OutputCtrlNames?.Length; i++)
                {
                    HTuple hTuple = RetProcedureCall.GetOutputCtrlParamTuple(OutputCtrlNames[i].S);
                    Temp_hTuple_OutputCtrl[i] = new HTupleVector(hTuple);
                }
                //将存储结果输出
                hObj_OutputIconic = Temp_hObj_OutputIconic.ToArray();
                hTuple_OutputCtrl = Temp_hTuple_OutputCtrl;


                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "CallProcedure Fail!" + ex.Message;
                hObj_OutputIconic = null;
                hTuple_OutputCtrl = null;
                return false;
            }
        }

        public bool UnloadProcedure(string procedureName, out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "UnloadProcedure Success!";
            try
            {
                myEngine.UnloadProcedure(procedureName);
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "UnloadProcedure Fail!" + ex.Message;
                return false;
            }

        }


        public bool UnloadAllProcedures(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "UnloadAllProcedures Success!";
            try
            {
                myEngine.UnloadAllProcedures();
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "UnloadAllProcedures Fail!" + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// 销毁引擎
        /// </summary>
        /// <param name="ErrorCode">错误代码</param>
        /// <param name="ErrorText">错误信息</param>
        /// <returns></returns>
        public bool DeInit(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "DeInit Success!";
            try
            {
                myEngine.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "DeInit Fail!" + ex.Message;
                return false;
            }
        }

        public bool StartDebugServer(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "StartDebugServer Success!";
            try
            {
                myEngine.StartDebugServer();
              
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "StartDebugServer Fail!" + ex.Message;
                return false;
            }
        }

        public bool StopDebugServer(out int ErrorCode, out string ErrorText)
        {
            ErrorCode = 0;
            ErrorText = "StopDebugServer Success!";
            try
            {
                myEngine.StopDebugServer();

                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = "StopDebugServer Fail!" + ex.Message;
                return false;
            }
        }
    }
}



